home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / mawk10.zip / REXP0.C < prev    next >
C/C++ Source or Header  |  1991-10-05  |  11KB  |  453 lines

  1.  
  2. /********************************************
  3. rexp0.c
  4. copyright 1991, Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the AWK programming language.
  8.  
  9. Mawk is distributed without warranty under the terms of
  10. the GNU General Public License, version 2, 1991.
  11. ********************************************/
  12.  
  13. /*$Log:    rexp0.c,v $
  14.  * Revision 3.4  91/08/13  09:10:05  brennan
  15.  * VERSION .9994
  16.  * 
  17.  * Revision 3.3  91/07/19  07:29:24  brennan
  18.  * backslash at end of regular expression now stands for backslash
  19.  * 
  20.  * Revision 3.2  91/07/19  06:58:23  brennan
  21.  * removed small bozo in processing of escape characters
  22.  * 
  23.  * Revision 3.1  91/06/07  10:33:20  brennan
  24.  * VERSION 0.995
  25.  * 
  26.  * Revision 1.2  91/06/05  08:59:36  brennan
  27.  * changed RE_free to free
  28.  * 
  29.  * Revision 1.1  91/06/03  07:10:15  brennan
  30.  * Initial revision
  31.  * 
  32. */
  33.  
  34. /*  lexical scanner  */
  35.  
  36. #include  "rexp.h"
  37.  
  38. /* static functions */
  39. static int  PROTO( do_str, (int, char **, MACHINE *) ) ;
  40. static int  PROTO( do_class, (char **, MACHINE *) ) ;
  41. static int  PROTO( escape, (char **) ) ;
  42. static BV   *PROTO( store_bvp, (BV *) ) ;
  43. static int  PROTO( ctohex, (int) ) ;
  44.  
  45.  
  46. #ifndef  EG  /* if EG make next array visible */
  47. static
  48. #endif
  49. char  RE_char2token[ '|' + 1 ] = {
  50. 0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
  51. 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,9,13,13,13,
  52. 6,7,3,4,13,13,10,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
  53. 13,13,5,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
  54. 13,13,13,13,13,13,13,13,13,13,11,12,13,8,13,13,13,13,13,13,
  55. 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
  56. 13,13,13,13,1} ;
  57.  
  58. #define  char2token(x) ( (unsigned char)(x) > '|' ? T_CHAR : RE_char2token[x] )
  59.  
  60. #define NOT_STARTED    (-1)
  61.  
  62. static  int  prev  ;
  63. static  char   *lp  ;     /*  ptr to reg exp string  */
  64. static  unsigned re_len ;
  65.  
  66.  
  67. void  RE_lex_init( re )
  68.   char *re ;
  69.   lp = re ;
  70.   re_len = strlen(re) + 1  ;
  71.   prev = NOT_STARTED ;
  72.   RE_run_stack_init() ;
  73. }
  74.   
  75.  
  76. int   RE_lex( mp )
  77.   MACHINE  *mp ;
  78. { register int c ;
  79.  
  80.   switch( c = char2token(*lp) )
  81.    {
  82.      case T_OR :
  83.      case T_PLUS :
  84.      case T_STAR :
  85.      case T_Q :
  86.      case T_RP :
  87.            lp++ ;  return  prev = c ;
  88.      case T_SLASH :
  89.            break ;
  90.  
  91.      case 0   :   return 0 ;
  92.      
  93.      case T_LP :
  94.            switch( prev )
  95.            { 
  96.              case T_CHAR :
  97.              case T_STR  :
  98.              case T_ANY :
  99.              case T_CLASS :
  100.              case T_START :
  101.              case T_RP :
  102.              case T_PLUS :
  103.              case T_STAR :
  104.              case T_Q :
  105.              case T_U :
  106.                   return prev = T_CAT ;
  107.              default  :
  108.                   lp++ ;
  109.                   return prev = T_LP ;
  110.            }
  111.    }
  112.  
  113.   /*  *lp  is  an operand, but implicit cat op is possible   */
  114.   switch( prev )
  115.    { case  NOT_STARTED :
  116.      case  T_OR :
  117.      case  T_LP :
  118.      case T_CAT :
  119.  
  120.           switch( c )
  121.            { case  T_ANY : 
  122.              { static plus_is_star_flag = 0 ;
  123.  
  124.                   if ( * ++lp == '*' )
  125.                   { lp++ ;  *mp = RE_u() ;
  126.                     return  prev = T_U ; }
  127.                   else
  128.                   if ( *lp == '+' )
  129.                       if ( plus_is_star_flag )
  130.                       { lp++ ;  *mp = RE_u() ;
  131.                         plus_is_star_flag = 0 ;
  132.                         return prev = T_U ;
  133.                       }
  134.                       else
  135.                       { plus_is_star_flag = 1 ;
  136.                         lp-- ; *mp = RE_any() ;
  137.                         return prev = T_ANY ;
  138.                       }
  139.                   else  
  140.                   { *mp = RE_any() ;
  141.                     prev = T_ANY ;
  142.                   }
  143.               }
  144.               break ;
  145.                     
  146.              case  T_SLASH :
  147.                   lp++ ; c = escape(&lp) ;
  148.                   prev = do_str(c, &lp, mp) ;
  149.                   break ;
  150.  
  151.              case  T_CHAR  :
  152.                   c = *lp++ ;
  153.                   prev = do_str(c, &lp, mp) ;
  154.                   break ;
  155.  
  156.              case T_CLASS : prev = do_class(&lp, mp) ;
  157.                             break ;
  158.  
  159.              case T_START : *mp = RE_start() ; lp++ ;
  160.                             prev = T_START ;
  161.                             break ;
  162.  
  163.              case T_END :  
  164.                      lp++ ; *mp = RE_end() ;
  165.                      return  prev = T_END ;
  166.  
  167.              default :
  168.                      RE_panic("bad switch in RE_lex") ;
  169.            }
  170.            break ;
  171.  
  172.      default : /* don't advance the pointer, return T_CAT */
  173.           return prev = T_CAT ;
  174.     }
  175.     /* check for end character */
  176.     if ( *lp == '$' )
  177.     { mp->start->type += END_ON ; lp++ ; }
  178.     return prev ;
  179. }
  180.  
  181. static  int  do_str( c, pp, mp)
  182.   int c ; /* the first character */
  183.   char **pp ;  /* where to put the re_char pointer on exit */
  184.   MACHINE  *mp ;  /* where to put the string machine */
  185. { register char *p , *s ;
  186.   char *str ;
  187.   unsigned len ;
  188.  
  189.  
  190.   p = *pp ;
  191.   s = str = RE_malloc( re_len ) ;
  192.   *s++ = c ;  len = 1 ;
  193.  
  194.   while ( 1 )
  195.   { char *save ;
  196.   
  197.     switch( char2token(*p) )
  198.     {
  199.       case  T_CHAR :  *s++ = *p++ ;
  200.                       break ;
  201.       case  T_SLASH :
  202.                       save = ++p ;
  203.                       *s++ = escape(&save) ;
  204.                       p = save ;
  205.                       break ;
  206.  
  207.       default  :  goto  out ;
  208.     }
  209.     len++ ;
  210.   }
  211. out:
  212.   /* if len > 1 and we failed on a ? + or * , need to back up */
  213.   if ( len > 1 && (*p == '*' || *p == '+' || *p == '?' ) )
  214.   { len-- ; p-- ; s-- ; }
  215.  
  216.   *s = 0 ;
  217.   *pp = p ;
  218.   *mp = RE_str((char *) RE_realloc(str, len+1) , len) ;
  219.   return  T_STR ;
  220. }
  221.  
  222.  
  223. /*--------------------------------------------
  224.   BUILD A CHARACTER CLASS
  225.  *---------------------------*/
  226.  
  227. #define  on( b, x)  ( (b)[(x)>>3] |= ( 1 << ((x)&7) ))
  228.  
  229. static  void  PROTO(block_on, (BV,int,int) ) ;
  230.  
  231. static  void  block_on( b, x, y)
  232.   BV b ; int x, y ;  /* must call with x<=y */
  233. { int lo = x >> 3 ;
  234.   int hi = y >> 3 ;
  235.   int  i, j, bit  ;
  236.  
  237.   if ( lo == hi )
  238.     { j = x&7 ; bit =  1 << j ; i = (y&7) - j + 1 ;
  239.       for ( ; i ; i-- , bit <<= 1 )  b[lo] |= bit ; }
  240.   else
  241.     { for ( i = lo + 1 ; i <= hi - 1 ; i++ )  b[i] = 0xff ;
  242.       b[lo] |= ( 0xff << (x&7) ) ;
  243.       b[hi] |= ~( 0xff << ((y&7)+1)) ;
  244.     }
  245. }
  246.  
  247. /* build a BV for a character class.
  248.    *start points at the '['
  249.    on exit:   *start points at the character after ']'
  250.               mp points at a machine that recognizes the class
  251. */
  252.  
  253. static int  do_class( start, mp)
  254.   char **start ; MACHINE  *mp ;
  255. { register char *p ;
  256.   register BV   *bvp ;
  257.   int  prev ;
  258.   char *q , *t;
  259.   int  cnt ;
  260.   int comp_flag ;
  261.  
  262.   p = (*start) + 1 ;
  263.   if ( *p == ']' || *p == '^' && *(p+1) == ']' )
  264.          RE_error_trap(-E3) ;
  265.   while ( 1 )  /* find the back of the class */
  266.     { if ( ! (q = strchr(p,']')) )  /* no closing bracket */
  267.          RE_error_trap(-E3) ;
  268.       p = q-1 ;
  269.       cnt = 0 ;
  270.       while ( *p == '\\') { cnt++ ; p-- ; }
  271.       if ( (cnt & 1) == 0 )  /* even number of \ */  break ;
  272.       p = q+1 ;
  273.     }
  274.   /*  q  now  pts at the back of the class   */
  275.   p = (*start) + 1 ;
  276.   *start = q + 1 ;
  277.  
  278.   bvp = (BV *) RE_malloc( sizeof(BV) ) ;
  279.   (void) memset( bvp, 0, SIZE_T(sizeof(BV)) ) ;
  280.  
  281.   comp_flag = *p == '^' ? p++ , 1 : 0 ;
  282.   prev = -1 ;  /* indicates  -  cannot be part of a range  */
  283.  
  284.   while ( p < q )
  285.   {
  286.      switch( *p )
  287.       { case '\\' :
  288.           t = ++p ;
  289.           prev = escape(&t) ;
  290.           on(*bvp, prev) ;
  291.           p = t ;
  292.           continue ;
  293.  
  294.         case '-' :
  295.           if ( prev == -1 || p+1 == q || prev > *(p+1) )
  296.              { prev = '-' ; on(*bvp, '-') ; }
  297.           else
  298.              { p++ ;
  299.                block_on(*bvp, prev, *p) ;
  300.                prev = -1 ;
  301.              }
  302.           break ;
  303.  
  304.         default :
  305.           prev = *p ;
  306.           on(*bvp, *p) ;
  307.           break ;
  308.       }
  309.       p++ ;
  310.   }
  311.  
  312.   if ( comp_flag )
  313.     for ( p = (char *) bvp ; p < (char *) bvp + sizeof(BV) ; p++)  *p = ~*p ;
  314.  
  315.   /* make sure zero is off */
  316.   (*bvp)[0] &= 0xfe ;
  317.  
  318.   *mp = RE_class( store_bvp( bvp ) ) ;
  319.   return  T_CLASS ;
  320. }
  321.  
  322.  
  323. /* storage for bit vectors so they can be reused ,
  324.    stored in an unsorted linear array 
  325.    the array grows as needed
  326. */
  327.  
  328. #define         BV_GROWTH       6
  329.  
  330. static BV *store_bvp( bvp )
  331.   BV *bvp ;
  332. {
  333.   static BV **bv_base, **bv_limit ;
  334.   static BV **bv_next ; /* next empty slot in the array */
  335.  
  336.   register BV **p ;
  337.   unsigned t ;
  338.  
  339.  
  340.   if ( bv_next == bv_limit ) /* need to grow */
  341.   {
  342.     if ( ! bv_base )  /* first growth */
  343.     {  t = 0 ; bv_base = (BV**)RE_malloc(BV_GROWTH*sizeof(BV*)) ; }
  344.     else 
  345.     { t = bv_next - bv_base ;
  346.       bv_base = (BV**) RE_realloc(bv_base, (t+BV_GROWTH)*sizeof(BV*)) ;
  347.     }
  348.  
  349.     bv_next = bv_base + t ;
  350.     bv_limit = bv_next + BV_GROWTH ;
  351.   }
  352.  
  353.   /* put bvp in bv_next as a sentinal */
  354.   *bv_next = bvp ;
  355.   p = bv_base ;
  356.   while ( memcmp(*p, bvp, SIZE_T(sizeof(BV))) )  p++ ;
  357.  
  358.   if ( p == bv_next )  /* it is new */
  359.         bv_next++ ;
  360.   else  /* we already have it */  free(bvp) ;
  361.  
  362.   return *p ;
  363. }
  364.   
  365.  
  366. /* ----------   convert escape sequences  -------------*/
  367.  
  368. #define isoctal(x)  ((x)>='0'&&(x)<='7')
  369.  
  370. #define  NOT_HEX        16
  371. static char hex_val['f' - 'A' + 1] = {
  372. 10,11,12,13,14,15, 0, 0,
  373.  0, 0, 0, 0, 0, 0, 0, 0,
  374.  0, 0, 0, 0, 0, 0, 0, 0,
  375.  0, 0, 0, 0, 0, 0, 0, 0,
  376. 10,11,12,13,14,15 } ;
  377.  
  378. /* interpret 1 character as hex */
  379. static int ctohex( c )
  380.   register int c ;
  381. { int t ;
  382.  
  383.   if ( c >= '0' && c <= '9' )  return c - '0' ;
  384.  
  385.   if ( c >= 'A' && c <= 'f' && ( t = hex_val[c-'A'] ))  return t ;
  386.  
  387.   return NOT_HEX ;
  388. }
  389.  
  390. #define  ET_END     7
  391.  
  392. static struct { char in , out ; } escape_test[ET_END+1] = {
  393. 'n' , '\n',
  394. 't' , '\t',
  395. 'f' , '\f',
  396. 'b' , '\b',
  397. 'r' , '\r',
  398. 'a' , '\07',
  399. 'v' , '\013',
  400. 0 , 0 } ;
  401.  
  402.  
  403. /*-----------------
  404.   return the char 
  405.   and move the pointer forward
  406.   on entry *s -> at the character after the slash
  407.  *-------------------*/
  408.  
  409. static int escape(start_p)
  410.   char **start_p ;
  411. { register char *p = *start_p ;
  412.   register unsigned x ;
  413.   unsigned xx ;
  414.   int i ;
  415.  
  416.   
  417.   escape_test[ET_END].in = *p ;
  418.   i = 0 ;
  419.   while ( escape_test[i].in != *p ) i++ ;
  420.   if ( i != ET_END )  /* in table */
  421.   { *start_p = p + 1 ;
  422.     return  escape_test[i].out ;
  423.   }
  424.  
  425.   if ( isoctal(*p) )
  426.   { x = *p++ - '0' ;
  427.     if ( isoctal(*p) )
  428.     { x = (x<<3) + *p++ - '0' ;
  429.       if ( isoctal(*p) )
  430.          x = (x<<3) + *p++ - '0' ;
  431.     }
  432.     *start_p = p ;
  433.     return  x & 0xff ;
  434.   }
  435.  
  436.   if ( *p == 0 )  return '\\' ;
  437.  
  438.   if ( *p++ == 'x' ) /* might be a hex digit */
  439.   {  if ( (x = ctohex(*p)) == NOT_HEX ) 
  440.      { *start_p  = p ;  return 'x' ; }
  441.  
  442.      /* look for another hex digit */
  443.      if ( (xx = ctohex(* ++p)) != NOT_HEX )
  444.      { x = (x<<4) + xx ; p++ ; }
  445.  
  446.      *start_p = p ; return x ;
  447.   }
  448.   /* anything else \c -> c */
  449.   *start_p = p ;
  450.   return p[-1]  ;
  451. }
  452.